#include "StdAfx.h"
#include "Settings.h"




#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/sax/HandlerBase.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/dom/DOMElement.hpp>
#include <xercesc/dom/DOMDocument.hpp>
#include <xercesc/dom/DOMNodeList.hpp>
#include <xercesc/util/OutOfMemoryException.hpp>
#include <xercesc/dom/DOMLSSerializer.hpp>
#include <xercesc/framework/LocalFileFormatTarget.hpp>

#include <iostream>
#include <string>
#include <sstream>
#include <ctime>

using namespace std;
using namespace xercesc;
// the max number that it can start skype process at same time.
int Settings::m_multiProcessN = Settings::s_defaultProcessNumber;
// the time of client no responding
int Settings::m_clientTimeOut = Settings::s_defaultClientTimeOut;
// the time of client no responding started from calling.
int Settings::m_callTimeOut = Settings::s_defaultCallTimeOut;
// the max total call by one user.
int Settings::m_maxTotalCallTime = Settings::s_defaultMaxTotalCallTime;
// the max one calling time.
int Settings::m_maxOneCallTime = Settings::s_defaultMaxOneCallTime;

Settings::Settings(){
}

Settings::~Settings(void) {
}

void Settings::readConfig(const string& filename) {
	try {
		XMLPlatformUtils::Initialize();
	} catch (const XMLException& toCatch) {
		char* message = XMLString::transcode(toCatch.getMessage());
		cout << "Error during initialization! :\n" << message << "\n";
		XMLString::release(&message);
		return;
	}

	XercesDOMParser* parser = new XercesDOMParser();
	parser->setValidationScheme(XercesDOMParser::Val_Never);
	parser->setDoNamespaces(false); // optional

	ErrorHandler* errHandler = (ErrorHandler*) new HandlerBase();
	parser->setErrorHandler(errHandler);

	try {
		parser->parse(filename.c_str());
		DOMDocument* doc = parser->getDocument();
		DOMElement* root = doc->getDocumentElement();

		m_multiProcessN = s_defaultProcessNumber;
		m_clientTimeOut = s_defaultClientTimeOut;
		m_callTimeOut = s_defaultCallTimeOut;
		m_maxTotalCallTime = s_defaultMaxTotalCallTime;
		m_maxOneCallTime = s_defaultMaxOneCallTime;

		DOMNodeList* setting = doc->getElementsByTagName(L"setting");
		int len = setting->getLength();
		if (len > 0) {
			DOMNamedNodeMap* attrs = setting->item(0)->getAttributes();

			DOMNode* process_number = attrs->getNamedItem(L"process_number");
			if (process_number != NULL) {
				wstringstream s;
				s << process_number->getNodeValue() << ends;
				s >> m_multiProcessN;
			}

			DOMNode* client_timeout = attrs->getNamedItem(L"client_timeout");
			if (client_timeout != NULL) {
				wstringstream s;
				s << client_timeout->getNodeValue() << ends;
				s >> m_clientTimeOut;
			}
			DOMNode* call_timeout = attrs->getNamedItem(L"call_timeout");
			if (call_timeout != NULL) {
				wstringstream s;
				s << call_timeout->getNodeValue() << ends;
				s >> m_callTimeOut;
			}
			DOMNode* maxTotalCallTime = attrs->getNamedItem(
					L"max_total_call_time");
			if (maxTotalCallTime != NULL) {
				wstringstream s;
				s << maxTotalCallTime->getNodeValue() << ends;
				s >> m_maxTotalCallTime;
			}
			DOMNode* maxOneCallTime = attrs->getNamedItem(L"max_one_call_time");
			if (maxOneCallTime != NULL) {
				wstringstream s;
				s << maxOneCallTime->getNodeValue() << ends;
				s >> m_maxOneCallTime;
			}
		} else {

		}
	} catch (const XMLException& toCatch) {
		char* message = XMLString::transcode(toCatch.getMessage());
		cout << "Exception message is: \n" << message << "\n";
		XMLString::release(&message);
		return;
	} catch (const DOMException& toCatch) {
		char* message = XMLString::transcode(toCatch.msg);
		cout << "Exception message is: \n" << message << "\n";
		XMLString::release(&message);
		return;
	} catch (...) {
		cout << "Unexpected Exception \n";
		return;
	}

	delete parser;
	delete errHandler;
	XMLPlatformUtils::Terminate();
}
void Settings::writeConfig(const string& filename) {
}
void Settings::readUserInfo(const string& filename) {
	try {
		XMLPlatformUtils::Initialize();
	} catch (const XMLException& toCatch) {
		char* message = XMLString::transcode(toCatch.getMessage());
		cout << "Error during initialization! :\n" << message << "\n";
		XMLString::release(&message);
		return;
	}

	XercesDOMParser* parser = new XercesDOMParser();
	parser->setValidationScheme(XercesDOMParser::Val_Never);
	parser->setDoNamespaces(false); // optional

	ErrorHandler* errHandler = (ErrorHandler*) new HandlerBase();
	parser->setErrorHandler(errHandler);

	try {
		parser->parse(filename.c_str());
		DOMDocument* doc = parser->getDocument();
		DOMElement* root = doc->getDocumentElement();
		// users
		DOMXPathResult* result = doc->evaluate(L"/users/user", root, NULL,
				DOMXPathResult::UNORDERED_NODE_SNAPSHOT_TYPE, NULL);
		cout << "GetUsers:" << endl;
		for (int i = 0; i < result->getSnapshotLength(); i++) {
			result->snapshotItem(i);
			DOMNode* user = result->getNodeValue();
			if (!user)
				cout << "user element not found." << endl;
			DOMNamedNodeMap* attrs = user->getAttributes();
			if (!attrs) {
				cout << "there is no attribute in user element " << i << endl;
				continue;
			}

			string name_sstr = "no_name";
			UserInfo::user_type user_type = UserInfo::USER_TYPE_CALLER;
			string id_sstr = "no_id";
			string pwd_sstr = "no_password";
			int caller_time = 0;

			DOMNode* name_attr = attrs->getNamedItem(L"name");
			if (name_attr) {
				const XMLCh* name = name_attr->getNodeValue();
				wstring name_wstr = name;
				name_sstr = string(name_wstr.begin(), name_wstr.end());
				wcout << name_wstr << endl;
			}

			DOMNode* type_attr = attrs->getNamedItem(L"type");
			if (type_attr) {
				const XMLCh* usertype = type_attr->getNodeValue();

				if (wstring(usertype) == L"caller") {
					user_type = UserInfo::USER_TYPE_CALLER;
				} else if (wstring(usertype) == L"callee") {
					user_type = UserInfo::USER_TYPE_CALLEE;
				} else {
					throw("[Settings], cannot recognize user type.");
				}
			}

			DOMNode* id_attr = attrs->getNamedItem(L"id");
			if (id_attr) {
				const XMLCh* id = id_attr->getNodeValue();
				wstring id_wstr = id;
				id_sstr = string(id_wstr.begin(), id_wstr.end());
			}

			DOMNode* pwd_attr = attrs->getNamedItem(L"password");
			if (pwd_attr) {
				const XMLCh* pwd = pwd_attr->getNodeValue();
				wstring pwd_wstr = pwd;
				pwd_sstr = string(pwd_wstr.begin(), pwd_wstr.end());
			}

			DOMNode* callerTime = attrs->getNamedItem(L"caller_time");
			if (callerTime != NULL) {
				wstringstream s;
				s << callerTime->getNodeValue() << ends;
				s >> caller_time;
			}

			if (user_type == UserInfo::USER_TYPE_CALLER) {
				m_Callers.push_back(Caller(name_sstr, id_sstr, pwd_sstr, caller_time));
				cout << "<" << user->getNodeName() << " name=" << name_sstr
						<< " type=Caller id=" << id_sstr << " password="
						<< pwd_sstr << " caller_time=" << caller_time << ">" << endl;
			} else if (user_type == UserInfo::USER_TYPE_CALLEE) {
				m_Callees.push_back(Callee(name_sstr, id_sstr, pwd_sstr));
				cout << "<" << user->getNodeName() << " name=" << name_sstr
						<< " type=Callee id=" << id_sstr << " password="
						<< pwd_sstr << " caller_time=" << caller_time << ">" << endl;
			} else
				assert(0);
		}
		result->release();
	} catch (const XMLException& toCatch) {
		char* message = XMLString::transcode(toCatch.getMessage());
		cout << "Exception message is: \n" << message << "\n";
		XMLString::release(&message);
		return;
	} catch (const DOMException& toCatch) {
		char* message = XMLString::transcode(toCatch.msg);
		cout << "Exception message is: \n" << message << "\n";
		XMLString::release(&message);
		return;
	} catch (...) {
		cout << "Unexpected Exception \n";
		return;
	}

	delete parser;
	delete errHandler;
	XMLPlatformUtils::Terminate();
}

static void gAddAttribute(DOMElement*  e, XMLCh* name,  const string& v)
{
	assert(e);
	wstring wv(v.begin(), v.end());

	e->setAttribute(name, wv.c_str());
}
void Settings::writeUserInfo(const string& filename) {
    try
    {
        XMLPlatformUtils::Initialize();
    }

    catch(const XMLException& toCatch)
    {
        char *pMsg = XMLString::transcode(toCatch.getMessage());
        XERCES_STD_QUALIFIER cerr << "Error during Xerces-c Initialization.\n"
             << "  Exception message:"
             << pMsg;
        XMLString::release(&pMsg);
        return;
    }

   int errorCode = 0;
   {
       //  Nest entire test in an inner block.
       //  The tree we create below is the same that the XercesDOMParser would
       //  have created, except that no whitespace text nodes would be created.
       DOMImplementation* impl =  DOMImplementationRegistry::getDOMImplementation(L"Core");

       if (impl != NULL)
       {
           try
           {
               DOMDocument* doc = impl->createDocument(
                           0,                    // root element namespace URI.
                           L"users",         // root element name
                           0);                   // document type object (DTD).

               DOMElement* rootElem = doc->getDocumentElement();

               for(CallerList::const_iterator it = m_Callers.begin(); it != m_Callers.end(); it++) {
				   DOMElement*  userElem = doc->createElement(L"user");
				   rootElem->appendChild(userElem);
            	   // name
            	   gAddAttribute(userElem, L"name", it->GetName());
            	   // id
            	   gAddAttribute(userElem, L"id", it->GetCallId());
            	   // password
            	   gAddAttribute(userElem, L"password", it->GetPassword());
            	   // type
            	   gAddAttribute(userElem, L"type", "caller");
            	   // caller_time
				   char buf[1024];
				   itoa(it->totalCallTime()/1000, buf, 10);
            	   gAddAttribute(userElem, L"caller_time", buf);
               }

               for (CalleeList::const_iterator it = m_Callees.begin(); it != m_Callees.end(); it++) {
				   DOMElement*  userElem = doc->createElement(L"user");
				   rootElem->appendChild(userElem);
            	   // name
            	   gAddAttribute(userElem,  L"name", it->GetName());
            	   // id
            	   gAddAttribute(userElem,  L"id", it->GetCallId());
            	   // type
            	   gAddAttribute(userElem, L"type", "callee");
               }
               //
               // Now count the number of elements in the above DOM tree.
               //

               const XMLSize_t elementCount = doc->getElementsByTagName(L"*")->getLength();
               XERCES_STD_QUALIFIER cout << "The tree just created contains: " << elementCount
                    << " elements." << XERCES_STD_QUALIFIER endl;

               DOMLSSerializer * theSerializer =  impl->createLSSerializer();
			   LocalFileFormatTarget *myFormTarget = new LocalFileFormatTarget(filename.c_str()); 
			   DOMLSOutput *theOutput = ((DOMImplementationLS*)impl)->createLSOutput();
			   theOutput->setByteStream(myFormTarget);

			   theSerializer->write(doc, theOutput);
               doc->release();
			   theOutput->release();
			   theSerializer->release();
           }
           catch (const OutOfMemoryException&)
           {
               XERCES_STD_QUALIFIER cerr << "OutOfMemoryException" << XERCES_STD_QUALIFIER endl;
               errorCode = 5;
           }
           catch (const DOMException& e)
           {
               XERCES_STD_QUALIFIER cerr << "DOMException code is:  " << e.code << XERCES_STD_QUALIFIER endl;
               errorCode = 2;
           }
           catch (...)
           {
               XERCES_STD_QUALIFIER cerr << "An error occurred creating the document" << XERCES_STD_QUALIFIER endl;
               errorCode = 3;
           }
       }  // (inpl != NULL)
       else
       {
           XERCES_STD_QUALIFIER cerr << "Requested implementation is not supported" << XERCES_STD_QUALIFIER endl;
           errorCode = 4;
       }
   }

   XMLPlatformUtils::Terminate();
   return;
}
